package wml.clipstore.storage.clips;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Stack;

import test.beans.User;
import wml.clipstore.base.Entity;
import wml.clipstore.map.MapManager;
import wml.clipstore.utils.EntityUtils;
import CLIPSJNI.Environment;

class ClipsSaver {

	private MapManager manager;
	private Environment clips;

	public static void main(String[] args) {
		User u = new User();
		System.out.println((u instanceof Entity));
	}

	ClipsSaver(MapManager manager, Environment clips) {
		this.manager = manager;
		this.clips = clips;
	}

	public void save(Entity entity) {
		List<String> facts = this.toFacts(entity);
		this.deffacts(facts);
	}

	private void deffacts(List<String> facts) {
		// StringBuilder deffacts = new StringBuilder("(deffacts facts")
		// .append(new Date().getTime());
		// for (String fact : facts)
		// deffacts.append(fact);
		// deffacts.append(")");
		// System.out.println(deffacts);
		for (String fact : facts) {
			System.out.println(fact);
			clips.assertString(fact);
		}
	}

	private List<String> toFacts(Entity entity) {
		Set<Integer> entities = new HashSet<Integer>();
		List<String> facts = new ArrayList<String>();
		Stack<Object> toIntprt = new Stack<Object>();
		toIntprt.add(entity);
		while (!toIntprt.isEmpty()) {
			Object o = toIntprt.pop();
			if (o instanceof Entity) {
				interpret((Entity) o, entities, facts, toIntprt);
			} else if (o instanceof Collection) {
				interpret((Collection<?>) o, entities, facts, toIntprt);
			}
		}
		return facts;
	}

	private void interpret(Entity entity, Set<Integer> es, List<String> facts,
			Stack<Object> toIntprt) {
		if (es.contains(entity.hashCode()))
			return;
		es.add(entity.hashCode());
		StringBuilder fact = new StringBuilder("(")
				.append(entity.getClass().getName()).append("(identifier ")
				.append(entity.hashCode()).append("@")
				.append(entity.getClass().getName()).append(") (class ")
				.append(entity.getClass().getName()).append(")");
		List<Field> fields = manager.getStoredFields(entity.getClass());
		for (Field f : fields) {
			Object value = EntityUtils.getValue(entity, f);
			if (value instanceof Entity || value instanceof Collection) {
				fact.append("(").append(f.getName()).append(" ")
						.append(value.hashCode()).append("@")
						.append(value.getClass().getName()).append(")");
				toIntprt.add(value);
			} else {
				String className = (value == null) ? "null" : value.getClass()
						.getName();
				fact.append("(").append(f.getName()).append(" \"")
						.append(value).append("@").append(className)
						.append("\"").append(")");
			}
		}
		fact.append(")");
		facts.add(fact.toString());
	}

	private void interpret(Collection<?> entity, Set<Integer> es,
			List<String> facts, Stack<Object> toIntprt) {
		if (es.contains(entity.hashCode()))
			return;
		es.add(entity.hashCode());
		StringBuilder fact = new StringBuilder("(java.util.Collection")
				.append("(identifier ").append(entity.hashCode()).append("@")
				.append(entity.getClass().getName()).append(") (class ")
				.append(entity.getClass().getName()).append(") (items");
		for (Object value : entity) {
			if (value instanceof Entity || value instanceof Collection) {
				fact.append(" ").append(value.hashCode()).append("@")
						.append(entity.getClass().getName());
				toIntprt.add(value);
			} else {
				String className = (value == null) ? "null" : value.getClass()
						.getName();
				fact.append(" \"").append(value).append("@").append(className)
						.append("\"");
				fact.append(" ").append(value);
			}
		}
		facts.add(fact.append("))").toString());
	}
}
